package com.cn.tous.auth.oauth2.serializer;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;

import java.io.IOException;
import java.time.Instant;
import java.util.*;

public class OAuth2AuthorizationDeserializer  extends JsonDeserializer<OAuth2Authorization> {

    @Override
    public OAuth2Authorization deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.getCodec().readTree(p);

        String id = node.get("id").asText();
        String registeredClientId = node.get("registeredClientId").asText();
        String principalName = node.get("principalName").asText();
        String grantTypeValue = getValue( "value", node.get("authorizationGrantType"));
        AuthorizationGrantType grantType = new AuthorizationGrantType(grantTypeValue);

        Map<String, Object> attributes = new HashMap<>();
        JsonNode attributesNode = node.get("attributes");
        if (attributesNode != null && attributesNode.isObject()) {
            Iterator<Map.Entry<String, JsonNode>> fields = attributesNode.fields();
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> entry = fields.next();
                // 这里简化：只支持基本类型和字符串
                JsonNode val = entry.getValue();
                if (val.isTextual()) {
                    attributes.put(entry.getKey(), val.asText());
                } else if (val.isNumber()) {
                    attributes.put(entry.getKey(), val.asDouble());
                } else {
                    attributes.put(entry.getKey(), val.toString()); // fallback
                }
            }
        }

        OAuth2Authorization.Builder builder = OAuth2Authorization.withRegisteredClient(
                RegisteredClient.withId(registeredClientId)
                        .clientId("1")
                        .authorizationGrantType(grantType
                        ).build());
        // Tokens
        OAuth2AccessToken accessToken = deserializeToken(node.get("accessToken"), OAuth2AccessToken.class);
        if (accessToken != null) {
            builder.accessToken(accessToken)
                    .authorizedScopes(accessToken.getScopes());
        }

        OAuth2RefreshToken refreshToken = deserializeToken(node.get("refreshToken"), OAuth2RefreshToken.class);
        if (refreshToken != null) builder.refreshToken(refreshToken);

        OAuth2AuthorizationCode authorizationCode = deserializeToken(node.get("authorizationCode"), OAuth2AuthorizationCode.class);
        if (authorizationCode != null) builder.invalidate(authorizationCode);

        return builder // 注意：RegisteredClient 需单独加载
                .id(id)
                .principalName(principalName)
                .authorizationGrantType(grantType)
                .attributes(attrs -> attrs.putAll(attributes))
//                .authorizedScopes(getScopes(tokens)) // 从 access token 提取
//                .invalidate()
                .build();

    }

    private <T> T deserializeToken(JsonNode node, Class<T> OAuth2TokenType) {
        if (node == null || !node.isObject()) return null;
        JsonNode tokenNode = node.get("token");
        String tokenValue = tokenNode.get("tokenValue").asText();
        Instant issuedAt = instantFrom(tokenNode, "issuedAt");
        Instant expiresAt = instantFrom(tokenNode, "expiresAt");

        Set<String> scopes = new HashSet<>();
        JsonNode scopesNode = tokenNode.get("scopes");
        if (scopesNode != null && scopesNode.isArray()) {
            Iterator<JsonNode> iterator = scopesNode.iterator();
            while (iterator.hasNext()) {
                JsonNode next = iterator.next();
                next.forEach(s -> scopes.add(s.asText()));
            }

        }

        if (OAuth2TokenType == OAuth2AccessToken.class) {

            if (tokenNode.has("tokenType")
                    && !OAuth2AccessToken.TokenType.BEARER.getValue().equals(getValue( "value", tokenNode.get("tokenType")))) {
                throw  new RuntimeException("accessToke tokenType is not right");
            }

            OAuth2AccessToken accessToken = new OAuth2AccessToken(
                    OAuth2AccessToken.TokenType.BEARER,
                    tokenValue,
                    issuedAt,
                    expiresAt,
                    scopes
            );
            return (T) accessToken;
        }

        if (OAuth2TokenType == OAuth2RefreshToken.class) {
            OAuth2RefreshToken refreshToken = new OAuth2RefreshToken(tokenValue, issuedAt, expiresAt);
            return (T) refreshToken;
        }

        if (OAuth2TokenType == OAuth2AuthorizationCode.class) {
            OAuth2AuthorizationCode authCode = new OAuth2AuthorizationCode(tokenValue, issuedAt, expiresAt);
            return (T) authCode;

        }
        return null;
    }

    private Instant instantFrom(JsonNode node, String field) {
        JsonNode fieldNode = node.get(field);
        if (fieldNode != null ) {
            return Instant.parse(fieldNode.asText());
        }
        return null;
    }

    private String getValue(String key,JsonNode node){

        if (node.has(key)) {
            return node.get(key).asText();
        }
        return  node.asText();
    }



}
